acm: Provide the possibility to choose the VM label of domain-0 in the
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 29 Mar 2007 18:26:13 +0000 (19:26 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 29 Mar 2007 18:26:13 +0000 (19:26 +0100)
kernel line in grub.conf. The format is
ssidref=<ssidref>:sHype:<policy name>:<vm label>. The name of the
policy specified here must be the same name as the in the policy
provided as a module during boot, otherwise the policy will not be
accepted and the system then starts without a policy. The user tool
for 'xm dumppolicy' has been adapted to show which entry in the binary
policy is used by domain-0.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
tools/security/secpol_tool.c
tools/security/secpol_xml2bin.c
xen/acm/acm_chinesewall_hooks.c
xen/acm/acm_core.c
xen/acm/acm_null_hooks.c
xen/acm/acm_policy.c
xen/acm/acm_simple_type_enforcement_hooks.c
xen/include/acm/acm_core.h
xen/include/acm/acm_hooks.h

index 0b9c3e4acdffa9f35133faa29004fb6221475fbe..a4a782c7548191b854e93d4c876479ebca27ebca 100644 (file)
@@ -57,7 +57,7 @@ void usage(char *progname)
 
 /*************************** DUMPS *******************************/
 
-void acm_dump_chinesewall_buffer(void *buf, int buflen)
+void acm_dump_chinesewall_buffer(void *buf, int buflen, uint16_t chwall_ref)
 {
 
     struct acm_chwall_policy_buffer *cwbuf =
@@ -91,6 +91,8 @@ void acm_dump_chinesewall_buffer(void *buf, int buflen)
         for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
             printf("%02x ",
                    ntohs(ssids[i * ntohl(cwbuf->chwall_max_types) + j]));
+        if (i == chwall_ref)
+            printf(" <-- Domain-0");
     }
     printf("\n\nConfict Sets:\n");
     conflicts =
@@ -131,7 +133,7 @@ void acm_dump_chinesewall_buffer(void *buf, int buflen)
     }
 }
 
-void acm_dump_ste_buffer(void *buf, int buflen)
+void acm_dump_ste_buffer(void *buf, int buflen, uint16_t ste_ref)
 {
 
     struct acm_ste_policy_buffer *stebuf =
@@ -158,11 +160,14 @@ void acm_dump_ste_buffer(void *buf, int buflen)
         for (j = 0; j < ntohl(stebuf->ste_max_types); j++)
             printf("%02x ",
                    ntohs(ssids[i * ntohl(stebuf->ste_max_types) + j]));
+        if (i == ste_ref)
+            printf(" <-- Domain-0");
     }
     printf("\n\n");
 }
 
-void acm_dump_policy_buffer(void *buf, int buflen)
+void acm_dump_policy_buffer(void *buf, int buflen,
+                            uint16_t chwall_ref, uint16_t ste_ref)
 {
     struct acm_policy_buffer *pol = (struct acm_policy_buffer *) buf;
     char *policy_reference_name =
@@ -190,13 +195,15 @@ void acm_dump_policy_buffer(void *buf, int buflen)
         acm_dump_chinesewall_buffer(ALIGN8(buf +
                                      ntohl(pol->primary_buffer_offset)),
                                     ntohl(pol->len) -
-                                    ntohl(pol->primary_buffer_offset));
+                                    ntohl(pol->primary_buffer_offset),
+                                    chwall_ref);
         break;
 
     case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
         acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->primary_buffer_offset)),
                             ntohl(pol->len) -
-                            ntohl(pol->primary_buffer_offset));
+                            ntohl(pol->primary_buffer_offset),
+                            ste_ref);
         break;
 
     case ACM_NULL_POLICY:
@@ -212,13 +219,15 @@ void acm_dump_policy_buffer(void *buf, int buflen)
         acm_dump_chinesewall_buffer(ALIGN8(buf +
                                      ntohl(pol->secondary_buffer_offset)),
                                     ntohl(pol->len) -
-                                    ntohl(pol->secondary_buffer_offset));
+                                    ntohl(pol->secondary_buffer_offset),
+                                    chwall_ref);
         break;
 
     case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
         acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->secondary_buffer_offset)),
                             ntohl(pol->len) -
-                            ntohl(pol->secondary_buffer_offset));
+                            ntohl(pol->secondary_buffer_offset),
+                            ste_ref);
         break;
 
     case ACM_NULL_POLICY:
@@ -230,6 +239,27 @@ void acm_dump_policy_buffer(void *buf, int buflen)
     }
 }
 
+/************************** get dom0 ssidref *****************************/
+int acm_get_ssidref(int xc_handle, int domid, uint16_t *chwall_ref,
+                    uint16_t *ste_ref)
+{
+    int ret;
+    struct acm_getssid getssid;
+    char buf[4096];
+    struct acm_ssid_buffer *ssid = (struct acm_ssid_buffer *)buf;
+    getssid.interface_version = ACM_INTERFACE_VERSION;
+    set_xen_guest_handle(getssid.ssidbuf, buf);
+    getssid.ssidbuf_size = sizeof(buf);
+    getssid.get_ssid_by = ACM_GETBY_domainid;
+    getssid.id.domainid = domid;
+    ret = xc_acm_op(xc_handle, ACMOP_getssid, &getssid, sizeof(getssid));
+    if (ret == 0) {
+        *chwall_ref = ssid->ssidref  & 0xffff;
+        *ste_ref    = ssid->ssidref >> 16;
+    }
+    return ret;
+}
+
 /******************************* get policy ******************************/
 
 #define PULL_CACHE_SIZE                8192
@@ -239,12 +269,16 @@ int acm_domain_getpolicy(int xc_handle)
 {
     struct acm_getpolicy getpolicy;
     int ret;
+    uint16_t chwall_ref, ste_ref;
 
     memset(pull_buffer, 0x00, sizeof(pull_buffer));
     getpolicy.interface_version = ACM_INTERFACE_VERSION;
     set_xen_guest_handle(getpolicy.pullcache, pull_buffer);
     getpolicy.pullcache_size = sizeof(pull_buffer);
     ret = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy));
+    if (ret >= 0) {
+        ret = acm_get_ssidref(xc_handle, 0, &chwall_ref, &ste_ref);
+    }
 
     if (ret < 0) {
         printf("ACM operation failed: errno=%d\n", errno);
@@ -254,7 +288,9 @@ int acm_domain_getpolicy(int xc_handle)
     }
 
     /* dump policy  */
-    acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer));
+    acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer),
+                           chwall_ref, ste_ref);
+
     return ret;
 }
 
@@ -266,6 +302,7 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename)
     int ret, fd;
     off_t len;
     uint8_t *buffer;
+    uint16_t chwall_ssidref, ste_ssidref;
 
     if ((ret = stat(filename, &mystat))) {
         printf("File %s not found.\n", filename);
@@ -282,10 +319,14 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename)
         printf("File %s not found.\n", filename);
         goto free_out;
     }
+    ret =acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref);
+    if (ret < 0) {
+        goto free_out;
+    }
     if (len == read(fd, buffer, len)) {
         struct acm_setpolicy setpolicy;
         /* dump it and then push it down into xen/acm */
-        acm_dump_policy_buffer(buffer, len);
+        acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
         setpolicy.interface_version = ACM_INTERFACE_VERSION;
         set_xen_guest_handle(setpolicy.pushcache, buffer);
         setpolicy.pushcache_size = len;
index 581ede1b64c0971d63ada2dc25c5893536b49f85..4b8f1dc7cd22a4d4f32e78510c85b8104dc82ac2 100644 (file)
@@ -1163,7 +1163,8 @@ int write_binary(char *filename)
 
     u_int32_t len_ste = 0, len_chwall = 0, len_pr = 0;  /* length of policy components */
 
-    sscanf(policy_version_string,"%d.%d", &major, &minor);
+    if (policy_version_string)
+        sscanf(policy_version_string,"%d.%d", &major, &minor);
 
     /* open binary file */
     if ((fd =
index 05f95256d049bbfded1a40a79b5560e5e3ced6d2..c3797e90fcfa6466c4c1bf3568b3c2994fbcf94d 100644 (file)
@@ -41,6 +41,9 @@
 #include <acm/acm_core.h>
 #include <acm/acm_hooks.h>
 #include <acm/acm_endian.h>
+#include <acm/acm_core.h>
+
+ssidref_t dom0_chwall_ssidref = 0x0001;
 
 /* local cache structures for chinese wall policy */
 struct chwall_binary_policy chwall_bin_pol;
@@ -53,7 +56,7 @@ int acm_init_chwall_policy(void)
 {
     /* minimal startup policy; policy write-locked already */
     chwall_bin_pol.max_types = 1;
-    chwall_bin_pol.max_ssidrefs = 2;
+    chwall_bin_pol.max_ssidrefs = 1 + dom0_chwall_ssidref;
     chwall_bin_pol.max_conflictsets = 1;
     chwall_bin_pol.ssidrefs =
         (domaintype_t *) xmalloc_array(domaintype_t,
@@ -254,7 +257,7 @@ chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
      * more than one type is currently running */
 }
 
-static int chwall_set_policy(u8 * buf, u32 buf_size)
+static int chwall_set_policy(u8 * buf, u32 buf_size, int is_bootpolicy)
 {
     /* policy write-locked already */
     struct acm_chwall_policy_buffer *chwall_buf =
@@ -286,6 +289,12 @@ static int chwall_set_policy(u8 * buf, u32 buf_size)
         (chwall_buf->policy_version != ACM_CHWALL_VERSION))
         return -EINVAL;
 
+    /* during boot dom0_chwall_ssidref is set */
+    if (is_bootpolicy &&
+        (dom0_chwall_ssidref >= chwall_buf->chwall_max_ssidrefs)) {
+        goto error_free;
+    }
+
     /* 1. allocate new buffers */
     ssids =
         xmalloc_array(domaintype_t,
index d7becf35104f05436b2c76b6d486d65e39ceea58..57db1369f542d55a6d918c61443e39e83ec1cf0d 100644 (file)
@@ -62,18 +62,63 @@ struct acm_binary_policy acm_bin_pol;
 /* acm binary policy lock */
 DEFINE_RWLOCK(acm_bin_pol_rwlock);
 
+/* ACM's only accepted policy name */
+char polname[80];
+char *acm_accepted_boot_policy_name = NULL;
+
+static void __init set_dom0_ssidref(const char *val)
+{
+    /* expected format:
+         ssidref=<hex number>:<policy name>
+         Policy name must not have a 'space'.
+     */
+    const char *c;
+    int lo, hi;
+    int i;
+    int dom0_ssidref = simple_strtoull(val, &c, 0);
+
+    if (!strncmp(&c[0],":sHype:", 7)) {
+        lo = dom0_ssidref & 0xffff;
+        if (lo < ACM_MAX_NUM_TYPES && lo >= 1)
+            dom0_chwall_ssidref = lo;
+        hi = dom0_ssidref >> 16;
+        if (hi < ACM_MAX_NUM_TYPES && hi >= 1)
+            dom0_ste_ssidref = hi;
+        for (i = 0; i < sizeof(polname); i++) {
+            polname[i] = c[7+i];
+            if (polname[i] == '\0' || polname[i] == '\t' ||
+                polname[i] == '\n' || polname[i] == ' '  ||
+                polname[i] == ':') {
+                break;
+            }
+        }
+        polname[i] = 0;
+        acm_accepted_boot_policy_name = polname;
+    }
+}
+
+custom_param("ssidref", set_dom0_ssidref);
+
 int
 acm_set_policy_reference(u8 *buf, u32 buf_size)
 {
+    char *name = (char *)(buf + sizeof(struct acm_policy_reference_buffer));
     struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf;
+
+    if (acm_accepted_boot_policy_name != NULL) {
+        if (strcmp(acm_accepted_boot_policy_name, name)) {
+            printk("Policy's name '%s' is not the expected one '%s'.\n",
+                   name, acm_accepted_boot_policy_name);
+            return ACM_ERROR;
+        }
+    }
+
     acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len));
 
     if (!acm_bin_pol.policy_reference_name)
         return -ENOMEM;
+    strlcpy(acm_bin_pol.policy_reference_name, name, be32_to_cpu(pr->len));
 
-    strlcpy(acm_bin_pol.policy_reference_name,
-            (char *)(buf + sizeof(struct acm_policy_reference_buffer)),
-            be32_to_cpu(pr->len));
     printk("%s: Activating policy %s\n", __func__,
            acm_bin_pol.policy_reference_name);
     return 0;
@@ -190,7 +235,8 @@ acm_is_policy(char *buf, unsigned long len)
 
 static int
 acm_setup(char *policy_start,
-          unsigned long policy_len)
+          unsigned long policy_len,
+          int is_bootpolicy)
 {
     int rc = ACM_OK;
     struct acm_policy_buffer *pol;
@@ -202,7 +248,8 @@ acm_setup(char *policy_start,
     if (be32_to_cpu(pol->magic) != ACM_MAGIC)
         return rc;
 
-    rc = do_acm_set_policy((void *)policy_start, (u32)policy_len);
+    rc = do_acm_set_policy((void *)policy_start, (u32)policy_len,
+                           is_bootpolicy);
     if (rc == ACM_OK)
     {
         printkd("Policy len  0x%lx, start at %p.\n",policy_len,policy_start);
@@ -224,7 +271,10 @@ acm_init(char *policy_start,
     int ret = ACM_OK;
 
     /* first try to load the boot policy (uses its own locks) */
-    acm_setup(policy_start, policy_len);
+    acm_setup(policy_start, policy_len, 1);
+
+    /* a user-provided policy may have any name; only matched during boot */
+    acm_accepted_boot_policy_name = NULL;
 
     if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
     {
@@ -236,6 +286,9 @@ acm_init(char *policy_start,
     printk("%s: Loading default policy (%s).\n",
            __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY));
 
+    /* (re-)set dom-0 ssidref to default */
+    dom0_ste_ssidref = dom0_chwall_ssidref = 0x0001;
+
     if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) {
         ret = -EINVAL;
         goto out;
index 27d949378f9ced6a9af9aad74d999c1231783b32..f481b71ed46f0e867380e9ca8eeb4a2d027ec0d0 100644 (file)
@@ -33,7 +33,7 @@ null_dump_binary_policy(u8 *buf, u32 buf_size)
 }
 
 static int
-null_set_binary_policy(u8 *buf, u32 buf_size)
+null_set_binary_policy(u8 *buf, u32 buf_size, int is_bootpolicy)
 { 
     return ACM_OK;
 }
index 694bd9daa1b36bed46987c22532e8f9ea5ce457d..96186895c7fb81add5883dfe938658d638cc3755 100644 (file)
@@ -50,7 +50,7 @@ acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size)
         printk("%s: Error copying!\n",__func__);
         goto error_free;
     }
-    ret = do_acm_set_policy(policy_buffer, buf_size);
+    ret = do_acm_set_policy(policy_buffer, buf_size, 0);
 
  error_free:
     xfree(policy_buffer);
@@ -59,7 +59,7 @@ acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size)
 
 
 int
-do_acm_set_policy(void *buf, u32 buf_size)
+do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy)
 {
     struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
     uint32_t offset, length;
@@ -106,14 +106,16 @@ do_acm_set_policy(void *buf, u32 buf_size)
     length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
 
     if ( (offset + length) > buf_size ||
-         acm_primary_ops->set_binary_policy(buf + offset, length))
+         acm_primary_ops->set_binary_policy(buf + offset, length,
+                                            is_bootpolicy))
         goto error_lock_free;
 
     /* set secondary policy data */
     offset = be32_to_cpu(pol->secondary_buffer_offset);
     length = be32_to_cpu(pol->len) - offset;
     if ( (offset + length) > buf_size ||
-         acm_secondary_ops->set_binary_policy(buf + offset, length))
+         acm_secondary_ops->set_binary_policy(buf + offset, length,
+                                              is_bootpolicy))
         goto error_lock_free;
 
     memcpy(&acm_bin_pol.xml_pol_version,
index f5793a22d85235551197e393a86a141c61665132..e87d0a25c1c7b26cfdd6954281ea444dd195138c 100644 (file)
@@ -31,6 +31,9 @@
 #include <acm/acm_hooks.h>
 #include <asm/atomic.h>
 #include <acm/acm_endian.h>
+#include <acm/acm_core.h>
+
+ssidref_t dom0_ste_ssidref = 0x0001;
 
 /* local cache structures for STE policy */
 struct ste_binary_policy ste_bin_pol;
@@ -74,15 +77,21 @@ int acm_init_ste_policy(void)
 {
     /* minimal startup policy; policy write-locked already */
     ste_bin_pol.max_types = 1;
-    ste_bin_pol.max_ssidrefs = 2;
-    ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2);
-    memset(ste_bin_pol.ssidrefs, 0, 2);
+    ste_bin_pol.max_ssidrefs = 1 + dom0_ste_ssidref;
+    ste_bin_pol.ssidrefs =
+            (domaintype_t *)xmalloc_array(domaintype_t,
+                                          ste_bin_pol.max_types *
+                                          ste_bin_pol.max_ssidrefs);
 
     if (ste_bin_pol.ssidrefs == NULL)
         return ACM_INIT_SSID_ERROR;
 
- /* initialize state so that dom0 can start up and communicate with itself */
-    ste_bin_pol.ssidrefs[1] = 1;
+    memset(ste_bin_pol.ssidrefs, 0, sizeof(domaintype_t) *
+                                    ste_bin_pol.max_types *
+                                    ste_bin_pol.max_ssidrefs);
+
+    /* initialize state so that dom0 can start up and communicate with itself */
+    ste_bin_pol.ssidrefs[ste_bin_pol.max_types * dom0_ste_ssidref] = 1;
 
     /* init stats */
     atomic_set(&(ste_bin_pol.ec_eval_count), 0);
@@ -274,7 +283,7 @@ ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
 
 /* set new policy; policy write-locked already */
 static int
-ste_set_policy(u8 *buf, u32 buf_size)
+ste_set_policy(u8 *buf, u32 buf_size, int is_bootpolicy)
 {
     struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
     void *ssidrefsbuf;
@@ -305,6 +314,11 @@ ste_set_policy(u8 *buf, u32 buf_size)
     if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
         goto error_free;
 
+    /* during boot dom0_chwall_ssidref is set */
+    if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs)) {
+        goto error_free;
+    }
+
     arrcpy(ssidrefsbuf, 
            buf + ste_buf->ste_ssid_offset,
            sizeof(domaintype_t),
index 033a1fd4188db3165ecf8ae64fbd140f8415c2f6..a09294cfc9efd514906dfdfb548cb205d8bea094 100644 (file)
@@ -123,13 +123,20 @@ int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
 void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
 int acm_init_binary_policy(u32 policy_code);
 int acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size);
-int do_acm_set_policy(void *buf, u32 buf_size);
+int do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy);
 int acm_get_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size);
 int acm_dump_statistics(XEN_GUEST_HANDLE(void) buf, u16 buf_size);
 int acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE(void) buf, u16 buf_size);
 int acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook);
 int acm_set_policy_reference(u8 * buf, u32 buf_size);
 int acm_dump_policy_reference(u8 *buf, u32 buf_size);
+
+
+/* variables */
+extern ssidref_t dom0_chwall_ssidref;
+extern ssidref_t dom0_ste_ssidref;
+#define ACM_MAX_NUM_TYPES   (256)
+
 #endif
 
 /*
index 2ac8a4ab448ed7bc6d4f952bfde2b0d243192742..0a771dd794c9de402db65e903a4fa837cbc1bff3 100644 (file)
@@ -91,7 +91,8 @@ struct acm_operations {
     int  (*init_domain_ssid)           (void **ssid, ssidref_t ssidref);
     void (*free_domain_ssid)           (void *ssid);
     int  (*dump_binary_policy)         (u8 *buffer, u32 buf_size);
-    int  (*set_binary_policy)          (u8 *buffer, u32 buf_size);
+    int  (*set_binary_policy)          (u8 *buffer, u32 buf_size,
+                                        int is_bootpolicy);
     int  (*dump_statistics)            (u8 *buffer, u16 buf_size);
     int  (*dump_ssid_types)            (ssidref_t ssidref, u8 *buffer, u16 buf_size);
     /* domain management control hooks (can be NULL) */
@@ -347,14 +348,13 @@ static inline int acm_pre_grant_setup(domid_t id)
     }
 }
 
-/* predefined ssidref for DOM0 used by xen when creating DOM0 */
-#define ACM_DOM0_SSIDREF       0x00010001 
-
 static inline void acm_post_domain0_create(domid_t domid)
 {
     /* initialialize shared sHype security labels for new domain */
-    acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF);
-    acm_post_domain_create(domid, ACM_DOM0_SSIDREF);
+    int dom0_ssidref = dom0_ste_ssidref << 16 | dom0_chwall_ssidref;
+
+    acm_init_domain_ssid(domid, dom0_ssidref);
+    acm_post_domain_create(domid, dom0_ssidref);
 }
 
 static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)